//
//  GameModel.cpp
//  CandyDizzle
//
//  Created by Cloner Team on 8/2/14.
//
//

#include "GameModel.h"
static GameModel* sharedGameModel = NULL;
GameModel* GameModel::getInstance() {
    if (sharedGameModel == NULL){
        sharedGameModel = new GameModel();
    }
    return sharedGameModel;
}

GameModel::GameModel() {
    //sound
    this->soundModel = SoundModel::getInstance();
    this->soundModel->setEffectsVolume(1);
    this->soundModel->setBackgroundMusicVolume(1);
    this->hasIncreasedSpeed = false;
    this->correctAfterIncrease = 0;
    this->currentScore = -1;
    this->canChoose = false;
    this->displayResolutionSize = Point::ZERO;
    this->vectorMove = Point::ZERO;
    this->listeners = __Array::create();
    CC_SAFE_RETAIN(this->listeners);
    this->removedColors = __Array::create();
    CC_SAFE_RETAIN(this->removedColors);
    this->fullScreenAdsHandling = 0;
    this->loadInformation();
}

GameModel::~GameModel() {
    Utils::safeRelease(this->listeners);
    Utils::safeRelease(this->removedColors);
}

void GameModel::update(float dt) {
    Size gameSize = this->displayResolutionSize;
    this->soundModel->update(dt);
    if(this->gameState == GS_PLAY){
        //create new color
        if(this->colorQueue.size()>0){
            if(this->colorQueue.front()->label->getPositionY()<gameSize.height){
                this->canChoose = true;
            } else {
                this->canChoose = false;
            }
            Color* color = this->colorQueue.back();
            Label* label = color->label;
            if (label->getPositionY() <= gameSize.height +200) {
                this->createNewColor();
            }
        } else {
            this->createNewColor();
        }
        //remove correct color
        int sizeRemovedColors = (int)this->removedColors->count();
        for (int i = 0; i < sizeRemovedColors; i++) {
            Color* color = (Color*) this->removedColors->getObjectAtIndex(i);
            Utils::safeRelease(color);
            this->removedColors->removeObjectAtIndex(i);
        }
    }
}

void GameModel::initialize(){
     this->gameState = GS_MENU;
}

void GameModel::addListener(UGListener* listener) {
    if (this->listeners != NULL) {
        this->listeners->addObject(listener);
    }
}

void GameModel::createNewColor() {
    int randomCorrectColor = Utils::random()*4 + 1;
    
    int randomLabelColor = randomCorrectColor;
    while(randomLabelColor == randomCorrectColor) {
        randomLabelColor = Utils::random()*4 +1;
    }
    Label* newColorLabel = Utils::createLabel((char*)"", (char*)FONT_VPSALT, 60);
    switch(randomCorrectColor) {
        case RED: //RED
        {
            newColorLabel->setString((char*)TXT_RED);
            break;
        }
        case BLUE: //BLUE
        {
            newColorLabel->setString((char*)TXT_BLUE);
            break;
        }
        case GREEN: //GREEN
        {
            newColorLabel->setString((char*)TXT_GREEN);
            break;
        }
        case YELLOW: //YELLOW
        {
            newColorLabel->setString((char*)TXT_YELLOW);
            break;
        }
    }
    
    switch(randomLabelColor) {
        case RED: //RED
        {
            newColorLabel->setColor(Color3B(255,0,0));
            break;
        }
        case BLUE: //BLUE
        {
            newColorLabel->setColor(Color3B(0,0,255));
            break;
        }
        case GREEN: //GREEN
        {
            newColorLabel->setColor(Color3B(0,255,0));
            break;
        }
        case YELLOW: //YELLOW
        {
            newColorLabel->setColor(Color3B(255,206,49));
            break;
        }
    }
    Color* newColor = Color::create();
    CC_SAFE_RETAIN(newColor);
    newColor->setCorrectColor(randomCorrectColor);
    newColor->setlabelColor(randomLabelColor);
    newColor->label = newColorLabel;
    this->colorQueue.push_back(newColor);
    this->fireNewColor();
}

void GameModel::finishGame() {
    int size = this->colorQueue.size();
    for(int i=0 ;i < size; i++) {
        Color* color = this->colorQueue.front();
        this->colorQueue.pop_front();
        color->label->removeFromParentAndCleanup(true);
        Utils::safeRelease(color);
    }
}

void GameModel::handleCorrectChoice() {
    if(this->hasIncreasedSpeed == true) {
        this->correctAfterIncrease ++;
        if(this->correctAfterIncrease >=3) {
            this->correctAfterIncrease = 0;
            this->fireReturnToNormal();
            this->hasIncreasedSpeed = false;
        }
    }
    Color* color = this->colorQueue.front();
    this->colorQueue.pop_front();
    this->removedColors->addObject(color);
    FiniteTimeAction* fadeOutAction = FadeOut::create(0.2f);
    FiniteTimeAction* callDelAction = CallFuncN::create(CC_CALLBACK_1(GameModel::callbackDelColor, this));
    FiniteTimeAction* sequenceAction = Sequence::create(fadeOutAction, callDelAction, NULL);
    color->label->runAction(sequenceAction);
}

void GameModel::fireDisplayMenu(){
    if(this->listeners != NULL){
        for(int i=0;i<listeners->count();i++){
            GUIListener* listener = dynamic_cast<GUIListener*>(listeners->getObjectAtIndex(i));
            if(listener!=NULL){
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getDisplayMenu();
                if(handlerFunc != NULL && handlerObj != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }
}

void GameModel::fireDisplayGame(){
    if(this->listeners != NULL) {
        for (int i=0; i<this->listeners->count(); i++){
            GUIListener* listener = dynamic_cast<GUIListener*>(this->listeners->getObjectAtIndex(i));
            if (listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getDisplayGame();
                if (handlerFunc != NULL && handlerObj != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }
}

void GameModel::fireDisplayResult() {
    this->fullScreenAdsHandling = this->fullScreenAdsHandling + 1;
    if (this->fullScreenAdsHandling >=3){
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
        this->fullScreenAdsHandling = 0;
        AppUtils::showAdFullscreen();
#endif
        
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
        this->fullScreenAdsHandling = 0;
        Application* application = Application::getInstance();
        application->openURL(":setFullAdVisible:");
#endif
    }

    if(this->listeners != NULL) {
        for(int i=0; i<this->listeners->count(); i++){
            GUIListener* listener = dynamic_cast<GUIListener*>(this->listeners->getObjectAtIndex(i));
            if (listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getDisplayResult();
                if (handlerFunc != NULL && handlerObj != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }
}

void GameModel::fireNewColor() {
    if(this->listeners != NULL){
        for(int i=0; i < this->listeners->count();i++){
            GameListener* listener = dynamic_cast<GameListener*>(this->listeners->getObjectAtIndex(i));
            if(listener != NULL){
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getNewColor();
                if (handlerFunc != NULL && handlerObj != NULL){
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }
}

void GameModel::fireIncreaseSpeed() {
    if(this->listeners != NULL) {
        for(int i=0; i< this->listeners->count(); i++){
            GameListener* listener = dynamic_cast<GameListener*>(this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getIncreaseSpeed();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }
}

void GameModel::fireCorrectChoice() {
    if(this->listeners != NULL) {
        for(int i=0; i< this->listeners->count(); i++){
            GameListener* listener = dynamic_cast<GameListener*>(this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getCorrectChoice();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }
}

void GameModel::fireReturnToNormal() {
    if(this->listeners != NULL) {
        for(int i=0; i< this->listeners->count(); i++){
            GameListener* listener = dynamic_cast<GameListener*>(this->listeners->getObjectAtIndex(i));
            if(listener != NULL) {
                Ref* handlerObj = listener->getHandlerObj();
                UGListenerFunc handlerFunc = listener->getReturnToNormal();
                if (handlerObj != NULL && handlerFunc != NULL) {
                    ((handlerObj)->*handlerFunc)(NULL);
                }
            }
        }
    }

}
void GameModel::callbackDelColor(Ref *data) {
    Label* label = (Label*) data;
    label->removeFromParentAndCleanup(true);
}

void GameModel::saveInformation() {
    char saveText[100];
    sprintf(saveText, TXT_SAVE_STRING, this->highScore, this->numberGames);
    Utils::writeFile(saveText, DOC_INFORMATION, false);
}

void GameModel::loadInformation() {
    Json* root;
    string fileData = Utils::readFile(DOC_INFORMATION, true, false, false);
    root = Json_create(fileData.data());
    if(root) {
        this->highScore = Json_getInt(root, "highscore", 0);
        this->numberGames = Json_getInt(root, "numberGames", 0);
    } else {
        this->highScore = 0;
        this->numberGames = 0;
    }
}